all repos — caroster @ a78d74bdc205a880e61fa477de33a5d876c6ea51

[Octree] Group carpool to your event https://caroster.io

frontend/pages/e/[uuid]/index.tsx (view raw)

  1import {useState, useReducer, useEffect} from 'react';
  2import {makeStyles} from '@material-ui/core/styles';
  3import {useTranslation} from 'react-i18next';
  4import {initializeApollo} from '../../../lib/apolloClient';
  5import useToastStore from '../../../stores/useToastStore';
  6import useEventStore from '../../../stores/useEventStore';
  7import Layout from '../../../layouts/Default';
  8import AddToMyEventDialog from '../../../containers/AddToMyEventDialog';
  9import TravelColumns from '../../../containers/TravelColumns';
 10import NewTravelDialog from '../../../containers/NewTravelDialog';
 11import VehicleChoiceDialog from '../../../containers/VehicleChoiceDialog';
 12import WelcomeDialog from '../../../containers/WelcomeDialog';
 13import EventBar from '../../../containers/EventBar';
 14import Loading from '../../../containers/Loading';
 15import OnBoardingTour from '../../../containers/OnBoardingTour';
 16import {
 17  useUpdateEventMutation,
 18  Event as EventType,
 19  useEventByUuidQuery,
 20  EventByUuidDocument,
 21  EditEventInput,
 22  useFindUserVehiclesQuery,
 23} from '../../../generated/graphql';
 24import ErrorPage from '../../_error';
 25import useProfile from '../../../hooks/useProfile';
 26import Fab from '../../../containers/Fab';
 27import useMediaQuery from '@material-ui/core/useMediaQuery';
 28import useBannerStore from '../../../stores/useBannerStore';
 29import DrawerMenu from '../../../containers/DrawerMenu';
 30
 31const POLL_INTERVAL = 10000;
 32
 33interface Props {
 34  event: EventType;
 35  eventUUID: string;
 36}
 37
 38const EventPage = props => {
 39  const {t} = useTranslation();
 40  const {event} = props;
 41  if (!event) return <ErrorPage statusCode={404} title={t`event.not_found`} />;
 42  return <Event {...props} />;
 43};
 44
 45const Event = (props: Props) => {
 46  const {eventUUID} = props;
 47  const bannerOffset = useBannerStore(s => s.offset);
 48  const classes = useStyles({bannerOffset});
 49  const {t} = useTranslation();
 50  const {user} = useProfile();
 51  const {data: {me: {profile: {vehicles = []} = {}} = {}} = {}, loading} =
 52    useFindUserVehiclesQuery();
 53  const addToast = useToastStore(s => s.addToast);
 54  const setEvent = useEventStore(s => s.setEvent);
 55  const eventUpdate = useEventStore(s => s.event);
 56  const setIsEditing = useEventStore(s => s.setIsEditing);
 57  const [updateEvent] = useUpdateEventMutation();
 58  const [isAddToMyEvent, setIsAddToMyEvent] = useState(false);
 59  const [openNewTravelContext, toggleNewTravel] = useState({opened: false});
 60  const [openVehicleChoice, toggleVehicleChoice] = useReducer(i => !i, false);
 61  const {data: {eventByUUID: event} = {}} = useEventByUuidQuery({
 62    pollInterval: POLL_INTERVAL,
 63    variables: {uuid: eventUUID},
 64  });
 65
 66  const onSave = async e => {
 67    try {
 68      const {uuid, ...data} = eventUpdate;
 69      const {id, __typename, travels, users, waitingList, ...input} = data;
 70      await updateEvent({
 71        variables: {uuid, eventUpdate: input as EditEventInput},
 72        refetchQueries: ['eventByUUID'],
 73      });
 74      setIsEditing(false);
 75    } catch (error) {
 76      console.error(error);
 77      addToast(t('event.errors.cant_update'));
 78    }
 79  };
 80
 81  useEffect(() => {
 82    if (event) setEvent(event as EventType);
 83  }, [event]);
 84
 85  const addTravelClickHandler =
 86    user && vehicles?.length != 0
 87      ? toggleVehicleChoice
 88      : () => toggleNewTravel({opened: true});
 89
 90  if (!event || loading) return <Loading />;
 91
 92  return (
 93    <Layout
 94      className={classes.layout}
 95      pageTitle={t('event.title', {title: event.name})}
 96      menuTitle={t('event.title', {title: event.name})}
 97      displayMenu={false}
 98    >
 99      <EventBar event={event} onAdd={setIsAddToMyEvent} onSave={onSave} />
100      <DrawerMenu />
101      <TravelColumns toggle={addTravelClickHandler} />
102      <Fab
103        onClick={addTravelClickHandler}
104        aria-label="add-car"
105        color="primary"
106        className={classes.bottomRight}
107      >
108        {t('travel.creation.title')}
109      </Fab>
110      <NewTravelDialog
111        context={openNewTravelContext}
112        toggle={() => toggleNewTravel({opened: false})}
113      />
114      <VehicleChoiceDialog
115        open={openVehicleChoice}
116        toggle={toggleVehicleChoice}
117        toggleNewTravel={toggleNewTravel}
118        vehicles={vehicles}
119      />
120      <AddToMyEventDialog
121        event={event}
122        open={isAddToMyEvent}
123        onClose={() => setIsAddToMyEvent(false)}
124      />
125      <WelcomeDialog />
126      <OnBoardingTour />
127    </Layout>
128  );
129};
130
131export async function getServerSideProps(ctx) {
132  const {uuid} = ctx.query;
133  const apolloClient = initializeApollo();
134  const {data = {}} = await apolloClient.query({
135    query: EventByUuidDocument,
136    variables: {uuid},
137  });
138  const {eventByUUID: event} = data;
139  const {host = ''} = ctx.req.headers;
140
141  return {
142    props: {
143      event,
144      eventUUID: uuid,
145      metas: {
146        title: event?.name || '',
147        url: `https://${host}${ctx.resolvedUrl}`,
148      },
149    },
150  };
151}
152
153const useStyles = makeStyles(theme => ({
154  layout: ({bannerOffset}) => ({
155    paddingTop: theme.mixins.toolbar.minHeight + bannerOffset,
156  }),
157  bottomRight: {
158    bottom: 0,
159    right: theme.spacing(6),
160
161    [theme.breakpoints.down('sm')]: {
162      right: theme.spacing(1),
163      bottom: 56,
164    },
165  },
166}));
167
168export default EventPage;